using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Services.Security.Enhanced
{
    /// <summary>
    /// 增强型安全认证服务
    /// 提供多层次安全验证、会话管理和威胁检测
    /// </summary>
    public class EnhancedSecurityService
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger<EnhancedSecurityService> _logger;
        private readonly ICacheService _cacheService;
        private readonly IHttpContextAccessor _httpContextAccessor;

        // 安全统计
        private readonly SecurityMetrics _metrics = new();

        public EnhancedSecurityService(
            IConfiguration configuration,
            ILogger<EnhancedSecurityService> logger,
            ICacheService cacheService,
            IHttpContextAccessor httpContextAccessor)
        {
            _configuration = configuration;
            _logger = logger;
            _cacheService = cacheService;
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// 增强型JWT令牌生成
        /// </summary>
    public async Task<SecurityTokenResult> GenerateEnhancedTokenAsync(ClaimsPrincipal user, TokenOptions? options = null)
        {
            options ??= new TokenOptions();
            
            try
            {
                var mapper = new JGSY.CMS.LowCode.Platform.Infrastructure.Configuration.AppSettingsMapper(_configuration);
                var jwtConfig = mapper.Bind<JGSY.CMS.LowCode.Platform.Infrastructure.Configuration.Models.JwtConfiguration>("Jwt");
                
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.Secret));
                var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                // 生成会话ID
                var sessionId = GenerateSessionId();
                var deviceId = GetDeviceFingerprint();
                var ipAddress = GetClientIpAddress();

                // 构建增强Claims
                var claims = new List<Claim>(user.Claims)
                {
                    new(SecurityClaimTypes.SessionId, sessionId),
                    new(SecurityClaimTypes.DeviceId, deviceId),
                    new(SecurityClaimTypes.IpAddress, ipAddress),
                    new(SecurityClaimTypes.TokenVersion, options.Version.ToString()),
                    new(SecurityClaimTypes.SecurityLevel, options.SecurityLevel.ToString()),
                    new(SecurityClaimTypes.IssuedAt, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())
                };

                // 获取JWT配置
                var jwtIssuer = _configuration["JWT:Issuer"] ?? "DefaultIssuer";
                var jwtAudience = _configuration["JWT:Audience"] ?? "DefaultAudience";

                // 创建Token
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(claims),
                    Expires = DateTime.UtcNow.Add(options.AccessTokenLifetime),
                    SigningCredentials = credentials,
                    Issuer = jwtIssuer,
                    Audience = jwtAudience,
                    NotBefore = DateTime.UtcNow
                };

                var tokenHandler = new JwtSecurityTokenHandler();
                var securityToken = tokenHandler.CreateToken(tokenDescriptor);
                var accessToken = tokenHandler.WriteToken(securityToken);

                // 生成刷新令牌
                var refreshToken = GenerateRefreshToken();

                // 存储会话信息
                var sessionInfo = new SessionInfo
                {
                    SessionId = sessionId,
                    UserId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty,
                    DeviceId = deviceId,
                    IpAddress = ipAddress,
                    AccessToken = accessToken,
                    RefreshToken = refreshToken,
                    CreatedAt = DateTime.UtcNow,
                    ExpiresAt = DateTime.UtcNow.Add(options.RefreshTokenLifetime),
                    SecurityLevel = options.SecurityLevel,
                    LastActivity = DateTime.UtcNow
                };

                await StoreSessionAsync(sessionInfo);

                // 记录安全事件
                await LogSecurityEventAsync(new SecurityEvent
                {
                    Type = SecurityEventType.TokenGenerated,
                    UserId = sessionInfo.UserId,
                    IpAddress = ipAddress,
                    DeviceId = deviceId,
                    Details = new { TokenVersion = options.Version, SecurityLevel = options.SecurityLevel }
                });

                _metrics.IncrementTokenGenerated();

                return new SecurityTokenResult
                {
                    AccessToken = accessToken,
                    RefreshToken = refreshToken,
                    ExpiresIn = (int)options.AccessTokenLifetime.TotalSeconds,
                    TokenType = "Bearer",
                    SessionId = sessionId,
                    SecurityLevel = options.SecurityLevel
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "令牌生成失败");
                throw new SecurityException("令牌生成失败", ex);
            }
        }

        /// <summary>
        /// 验证会话安全性
        /// </summary>
        public async Task<SecurityValidationResult> ValidateSessionSecurityAsync(string sessionId, string accessToken)
        {
            try
            {
                var sessionInfo = await GetSessionAsync(sessionId);
                if (sessionInfo == null)
                {
                    return SecurityValidationResult.Invalid("会话不存在");
                }

                var currentIp = GetClientIpAddress();
                var currentDevice = GetDeviceFingerprint();

                // 检查会话状态
                if (sessionInfo.IsRevoked)
                {
                    await LogSecurityEventAsync(new SecurityEvent
                    {
                        Type = SecurityEventType.RevokedTokenUsed,
                        UserId = sessionInfo.UserId,
                        SessionId = sessionId,
                        IpAddress = currentIp
                    });
                    return SecurityValidationResult.Invalid("会话已吊销");
                }

                // 检查过期
                if (sessionInfo.ExpiresAt < DateTime.UtcNow)
                {
                    return SecurityValidationResult.Invalid("会话已过期");
                }

                // 安全检查
                var securityChecks = new List<Task<SecurityCheckResult>>
                {
                    CheckIpAddressAsync(sessionInfo.IpAddress, currentIp),
                    CheckDeviceFingerprintAsync(sessionInfo.DeviceId, currentDevice),
                    CheckSuspiciousActivityAsync(sessionInfo.UserId, currentIp),
                    CheckTokenIntegrityAsync(sessionInfo.AccessToken, accessToken)
                };

                var results = await Task.WhenAll(securityChecks);
                var failedChecks = results.Where(r => !r.IsValid).ToList();

                if (failedChecks.Any())
                {
                    // 记录安全威胁
                    await LogSecurityEventAsync(new SecurityEvent
                    {
                        Type = SecurityEventType.SecurityThreatDetected,
                        UserId = sessionInfo.UserId,
                        SessionId = sessionId,
                        IpAddress = currentIp,
                        Details = failedChecks.Select(f => f.Reason).ToArray()
                    });

                    var highRiskChecks = failedChecks.Where(f => f.RiskLevel == RiskLevel.High).ToList();
                    if (highRiskChecks.Any())
                    {
                        // 高风险，立即吊销会话
                        await RevokeSessionAsync(sessionId, "高风险安全威胁");
                        return SecurityValidationResult.Invalid("安全威胁检测，会话已吊销");
                    }

                    // 中低风险，要求重新认证
                    return SecurityValidationResult.RequireReauth("检测到安全风险，需要重新认证");
                }

                // 更新会话活动时间
                sessionInfo.LastActivity = DateTime.UtcNow;
                await UpdateSessionAsync(sessionInfo);

                return SecurityValidationResult.Valid();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "会话安全验证失败: {SessionId}", sessionId);
                return SecurityValidationResult.Invalid("验证失败");
            }
        }

        /// <summary>
        /// 刷新令牌
        /// </summary>
    public async Task<SecurityTokenResult?> RefreshTokenAsync(string refreshToken, string sessionId)
        {
            try
            {
                var sessionInfo = await GetSessionAsync(sessionId);
                if (sessionInfo?.RefreshToken != refreshToken)
                {
                    await LogSecurityEventAsync(new SecurityEvent
                    {
                        Type = SecurityEventType.InvalidRefreshToken,
                        SessionId = sessionId,
                        IpAddress = GetClientIpAddress()
                    });
                    throw new SecurityException("无效的刷新令牌");
                }

                // 验证刷新令牌的合法性
                var validation = await ValidateSessionSecurityAsync(sessionId, sessionInfo.AccessToken);
                if (!validation.IsValid && validation.RequiresReauth)
                {
                    return null; // 需要重新认证
                }

                // 生成新的访问令牌
                var user = await GetUserPrincipalFromSessionAsync(sessionInfo);
                var newTokenResult = await GenerateEnhancedTokenAsync(user, new TokenOptions
                {
                    SecurityLevel = sessionInfo.SecurityLevel,
                    Version = sessionInfo.TokenVersion + 1
                });

                // 吊销旧令牌
                await RevokeSessionAsync(sessionId, "令牌刷新");

                return newTokenResult;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "令牌刷新失败: {SessionId}", sessionId);
                throw;
            }
        }

        /// <summary>
        /// 多因素认证验证
        /// </summary>
        public async Task<MfaValidationResult> ValidateMfaAsync(string userId, string code, MfaMethod method)
        {
            try
            {
                var mfaKey = $"mfa:{userId}:{method}";
                var storedCode = await _cacheService.GetAsync<string>(mfaKey);

                if (string.IsNullOrEmpty(storedCode))
                {
                    return MfaValidationResult.Invalid("验证码已过期");
                }

                // 使用时间常数比较防止时序攻击
                if (!CryptographicOperations.FixedTimeEquals(
                    Encoding.UTF8.GetBytes(code), 
                    Encoding.UTF8.GetBytes(storedCode)))
                {
                    await LogSecurityEventAsync(new SecurityEvent
                    {
                        Type = SecurityEventType.InvalidMfaCode,
                        UserId = userId,
                        IpAddress = GetClientIpAddress(),
                        Details = new { Method = method.ToString() }
                    });

                    _metrics.IncrementMfaFailure();
                    return MfaValidationResult.Invalid("验证码错误");
                }

                // 验证成功，删除验证码
                await _cacheService.RemoveAsync(mfaKey);

                await LogSecurityEventAsync(new SecurityEvent
                {
                    Type = SecurityEventType.MfaSuccess,
                    UserId = userId,
                    IpAddress = GetClientIpAddress(),
                    Details = new { Method = method.ToString() }
                });

                _metrics.IncrementMfaSuccess();
                return MfaValidationResult.Valid();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "MFA验证失败: {UserId}, {Method}", userId, method);
                return MfaValidationResult.Invalid("验证失败");
            }
        }

        /// <summary>
        /// 获取安全统计
        /// </summary>
        public SecurityMetrics GetSecurityMetrics()
        {
            return _metrics.GetSnapshot();
        }

        #region 私有方法

        private async Task<SecurityCheckResult> CheckIpAddressAsync(string originalIp, string currentIp)
        {
            if (originalIp == currentIp)
                return SecurityCheckResult.Valid();

            // 检查IP地址变化是否可疑
            var ipChangeKey = $"ip_change:{originalIp}:{currentIp}";
            var changeCount = await _cacheService.GetAsync<int>(ipChangeKey);
            
            if (changeCount > 3) // 频繁IP变化
            {
                return SecurityCheckResult.Invalid("频繁IP地址变化", RiskLevel.High);
            }

            // 记录IP变化
            await _cacheService.SetAsync(ipChangeKey, changeCount + 1, TimeSpan.FromMinutes(15));
            
            return SecurityCheckResult.Invalid("IP地址变化", RiskLevel.Medium);
        }

        private Task<SecurityCheckResult> CheckDeviceFingerprintAsync(string originalDevice, string currentDevice)
            => Task.FromResult(originalDevice == currentDevice 
                ? SecurityCheckResult.Valid() 
                : SecurityCheckResult.Invalid("设备指纹不匹配", RiskLevel.High));

        private async Task<SecurityCheckResult> CheckSuspiciousActivityAsync(string userId, string ipAddress)
        {
            // 检查短时间内的多次请求
            var activityKey = $"activity:{userId}:{ipAddress}";
            var activityCount = await _cacheService.GetAsync<int>(activityKey);
            
            if (activityCount > 100) // 1分钟内超过100次请求
            {
                return SecurityCheckResult.Invalid("可疑活动频率", RiskLevel.High);
            }

            await _cacheService.SetAsync(activityKey, activityCount + 1, TimeSpan.FromMinutes(1));
            return SecurityCheckResult.Valid();
        }

        private Task<SecurityCheckResult> CheckTokenIntegrityAsync(string originalToken, string currentToken)
            => Task.FromResult(originalToken == currentToken 
                ? SecurityCheckResult.Valid() 
                : SecurityCheckResult.Invalid("令牌完整性验证失败", RiskLevel.High));

        private string GenerateSessionId()
        {
            using var rng = RandomNumberGenerator.Create();
            var bytes = new byte[32];
            rng.GetBytes(bytes);
            return Convert.ToBase64String(bytes).Replace("+", "").Replace("/", "").Replace("=", "")[..32];
        }

        private string GenerateRefreshToken()
        {
            using var rng = RandomNumberGenerator.Create();
            var bytes = new byte[64];
            rng.GetBytes(bytes);
            return Convert.ToBase64String(bytes);
        }

        private string GetDeviceFingerprint()
        {
            var context = _httpContextAccessor.HttpContext;
            if (context == null) return "unknown";

            var userAgent = context.Request.Headers["User-Agent"].ToString();
            var acceptLanguage = context.Request.Headers["Accept-Language"].ToString();
            var acceptEncoding = context.Request.Headers["Accept-Encoding"].ToString();

            var fingerprint = $"{userAgent}|{acceptLanguage}|{acceptEncoding}";
            
            using var sha256 = SHA256.Create();
            var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(fingerprint));
            return Convert.ToHexString(hash)[..16];
        }

        private string GetClientIpAddress()
        {
            var context = _httpContextAccessor.HttpContext;
            if (context == null) return "unknown";

            // 考虑代理服务器
            var ipAddress = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (!string.IsNullOrEmpty(ipAddress))
            {
                ipAddress = ipAddress.Split(',')[0].Trim();
            }
            else
            {
                ipAddress = context.Request.Headers["X-Real-IP"].FirstOrDefault() 
                           ?? context.Connection.RemoteIpAddress?.ToString() 
                           ?? "unknown";
            }

            return ipAddress;
        }

        private async Task StoreSessionAsync(SessionInfo sessionInfo)
        {
            var key = $"session:{sessionInfo.SessionId}";
            await _cacheService.SetAsync(key, sessionInfo, sessionInfo.ExpiresAt - DateTime.UtcNow);
        }

    private async Task<SessionInfo?> GetSessionAsync(string sessionId)
        {
            var key = $"session:{sessionId}";
            return await _cacheService.GetAsync<SessionInfo>(key);
        }

        private async Task UpdateSessionAsync(SessionInfo sessionInfo)
        {
            await StoreSessionAsync(sessionInfo);
        }

        private async Task RevokeSessionAsync(string sessionId, string reason)
        {
            var sessionInfo = await GetSessionAsync(sessionId);
            if (sessionInfo != null)
            {
                sessionInfo.IsRevoked = true;
                sessionInfo.RevokedAt = DateTime.UtcNow;
                sessionInfo.RevocationReason = reason;
                await UpdateSessionAsync(sessionInfo);

                await LogSecurityEventAsync(new SecurityEvent
                {
                    Type = SecurityEventType.SessionRevoked,
                    UserId = sessionInfo.UserId,
                    SessionId = sessionId,
                    Details = new { Reason = reason }
                });
            }
        }

        private Task<ClaimsPrincipal> GetUserPrincipalFromSessionAsync(SessionInfo sessionInfo)
        {
            // 从会话信息重建用户主体
            var claims = new List<Claim>
            {
                new(ClaimTypes.NameIdentifier, sessionInfo.UserId),
                new(SecurityClaimTypes.SessionId, sessionInfo.SessionId)
            };

            return Task.FromResult(new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt")));
        }

        private async Task LogSecurityEventAsync(SecurityEvent securityEvent)
        {
            try
            {
                securityEvent.Id = Guid.NewGuid().ToString();
                securityEvent.Timestamp = DateTime.UtcNow;

                var eventKey = $"security_event:{securityEvent.Id}";
                await _cacheService.SetAsync(eventKey, securityEvent, TimeSpan.FromDays(30));

                _logger.LogWarning("安全事件: {Type}, 用户: {UserId}, IP: {IpAddress}, 详情: {Details}",
                    securityEvent.Type, securityEvent.UserId, securityEvent.IpAddress, 
                    JsonSerializer.Serialize(securityEvent.Details));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录安全事件失败");
            }
        }

        #endregion
    }

    #region 数据模型

    public class TokenOptions
    {
        public TimeSpan AccessTokenLifetime { get; set; } = TimeSpan.FromMinutes(15);
        public TimeSpan RefreshTokenLifetime { get; set; } = TimeSpan.FromDays(7);
        public SecurityLevel SecurityLevel { get; set; } = SecurityLevel.Standard;
        public int Version { get; set; } = 1;
    }

    public class SecurityTokenResult
    {
        public string AccessToken { get; set; } = string.Empty;
        public string RefreshToken { get; set; } = string.Empty;
        public int ExpiresIn { get; set; }
        public string TokenType { get; set; } = string.Empty;
        public string SessionId { get; set; } = string.Empty;
        public SecurityLevel SecurityLevel { get; set; }
    }

    public class SessionInfo
    {
        public string SessionId { get; set; } = string.Empty;
        public string UserId { get; set; } = string.Empty;
        public string DeviceId { get; set; } = string.Empty;
        public string IpAddress { get; set; } = string.Empty;
        public string AccessToken { get; set; } = string.Empty;
        public string RefreshToken { get; set; } = string.Empty;
        public DateTime CreatedAt { get; set; }
        public DateTime ExpiresAt { get; set; }
        public DateTime LastActivity { get; set; }
        public bool IsRevoked { get; set; }
        public DateTime? RevokedAt { get; set; }
        public string RevocationReason { get; set; } = string.Empty;
        public SecurityLevel SecurityLevel { get; set; }
        public int TokenVersion { get; set; } = 1;
    }

    public class SecurityValidationResult
    {
        public bool IsValid { get; set; }
        public bool RequiresReauth { get; set; }
        public string Message { get; set; } = string.Empty;

        public static SecurityValidationResult Valid() => new() { IsValid = true };
        public static SecurityValidationResult Invalid(string message) => new() { IsValid = false, Message = message };
        public static SecurityValidationResult RequireReauth(string message) => new() { RequiresReauth = true, Message = message };
    }

    public class SecurityCheckResult
    {
        public bool IsValid { get; set; }
        public string Reason { get; set; } = string.Empty;
        public RiskLevel RiskLevel { get; set; }

        public static SecurityCheckResult Valid() => new() { IsValid = true };
        public static SecurityCheckResult Invalid(string reason, RiskLevel riskLevel) => 
            new() { IsValid = false, Reason = reason, RiskLevel = riskLevel };
    }

    public class MfaValidationResult
    {
        public bool IsValid { get; set; }
        public string Message { get; set; } = string.Empty;

        public static MfaValidationResult Valid() => new() { IsValid = true };
        public static MfaValidationResult Invalid(string message) => new() { IsValid = false, Message = message };
    }

    public class SecurityEvent
    {
        public string Id { get; set; } = string.Empty;
        public DateTime Timestamp { get; set; }
        public SecurityEventType Type { get; set; }
        public string UserId { get; set; } = string.Empty;
        public string SessionId { get; set; } = string.Empty;
        public string IpAddress { get; set; } = string.Empty;
        public string DeviceId { get; set; } = string.Empty;
        public object? Details { get; set; }
    }

    public class SecurityMetrics
    {
        private long _tokensGenerated = 0;
        private long _mfaSuccesses = 0;
        private long _mfaFailures = 0;
        private long _securityThreats = 0;

        public void IncrementTokenGenerated() => Interlocked.Increment(ref _tokensGenerated);
        public void IncrementMfaSuccess() => Interlocked.Increment(ref _mfaSuccesses);
        public void IncrementMfaFailure() => Interlocked.Increment(ref _mfaFailures);
        public void IncrementSecurityThreat() => Interlocked.Increment(ref _securityThreats);

        public SecurityMetrics GetSnapshot() => new()
        {
            _tokensGenerated = this._tokensGenerated,
            _mfaSuccesses = this._mfaSuccesses,
            _mfaFailures = this._mfaFailures,
            _securityThreats = this._securityThreats
        };

        public long TokensGenerated => _tokensGenerated;
        public long MfaSuccesses => _mfaSuccesses;
        public long MfaFailures => _mfaFailures;
        public long SecurityThreats => _securityThreats;
        public double MfaSuccessRate => _mfaSuccesses + _mfaFailures > 0 ? (double)_mfaSuccesses / (_mfaSuccesses + _mfaFailures) : 0;
    }

    #endregion

    #region 枚举

    public enum SecurityLevel
    {
        Basic = 1,
        Standard = 2,
        High = 3,
        Critical = 4
    }

    public enum RiskLevel
    {
        Low = 1,
        Medium = 2,
        High = 3
    }

    public enum SecurityEventType
    {
        TokenGenerated,
        SessionRevoked,
        SecurityThreatDetected,
        InvalidRefreshToken,
        RevokedTokenUsed,
        MfaSuccess,
        InvalidMfaCode,
        SuspiciousActivity
    }

    public enum MfaMethod
    {
        SMS,
        Email,
        TOTP,
        Hardware
    }

    #endregion

    #region 自定义Claims类型

    public static class SecurityClaimTypes
    {
        public const string SessionId = "session_id";
        public const string DeviceId = "device_id";
        public const string IpAddress = "ip_address";
        public const string TokenVersion = "token_version";
        public const string SecurityLevel = "security_level";
        public const string IssuedAt = "iat";
    }

    #endregion

    #region 异常类

    public class SecurityException : Exception
    {
        public SecurityException(string message) : base(message) { }
        public SecurityException(string message, Exception innerException) : base(message, innerException) { }
    }

    #endregion
}
